
#include <wsnos.h>

/************************************************************/
extern task_cb g_task_cb[OSEL_MAX_PRIO];

osel_uint8_t osel_rdy_grp;

osel_uint8_t osel_rdy_tbl[(OSEL_MAX_PRIO/8) + 1];

static osel_int8_t osel_curr_prio = -1;
static osel_uint8_t first_malloc = OSEL_TRUE;

static osel_uint8_t const CODE osel_unmap_tbl[] =
{
    0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
};

/************************************************************/
static void osel_post_(event_pool_t *e, osel_uint8_t prio)
{
    task_cb *tcb = &g_task_cb[prio];
    OSEL_INT_LOCK();

    osel_rdy_grp |= osel_map_tbl[prio >> 3];
    osel_rdy_tbl[prio >> 3] |= osel_map_tbl[prio & 0x07];

    if (e->eblock->event_prio == OSEL_EPOOL_PRIO_HIG)
    {
        list_add(&(e->list), &tcb->queue);
        OSEL_INT_UNLOCK();
    }
    else
    {
        list_append(&(e->list), &tcb->queue);
        OSEL_INT_UNLOCK();
    }

    OSEL_POST_EXIT();
}

static event_block_t *fill_eblock(osel_signal_t sig, osel_param_t param,
                                  osel_epool_prio_t epool_prio)
{
    event_block_t *eblock = OSEL_NULL;
    eblock = osel_eblock_malloc(__EBLOCK_LINE1);
    OSEL_ASSERT(eblock != OSEL_NULL);

    if (eblock != OSEL_NULL)
    {
        eblock->type = sig;
        eblock->param = param;
        eblock->event_prio = epool_prio;
        eblock->cnt = 0;
    }

    return eblock;
}

void osel_post(osel_signal_t sig, osel_param_t param, osel_epool_prio_t epool_prio)
{
    event_pool_t *epool = OSEL_NULL;
    event_block_t *eblock = OSEL_NULL;

    OSEL_ASSERT(sig <= OSEL_STOP_SIG);

    OSEL_INT_LOCK();
    first_malloc = OSEL_TRUE;
    osel_uint8_t i = OSEL_DIM(osel_subscrlist[sig].bits);
    OSEL_INT_UNLOCK();

    do
    {
        OSEL_INT_LOCK();
        i--;
        osel_uint8_t temp = osel_subscrlist[sig].bits[i];

        while (temp != (osel_uint8_t)0)
        {
            OSEL_INT_LOCK();
            osel_uint8_t prio = osel_unmap_tbl[temp];
            temp &= ~osel_map_tbl[prio];
            prio += (i << 3);

            if (first_malloc == OSEL_TRUE)
            {
                first_malloc = OSEL_FALSE;
                eblock = fill_eblock(sig, param, epool_prio);
            }

            if (eblock != OSEL_NULL)
            {
                eblock->cnt ++;
            }

            epool = osel_epool_malloc(__EPOOL_LINE1);
            OSEL_ASSERT(epool != OSEL_NULL);
            epool->eblock = eblock;
            OSEL_INT_UNLOCK();
            OSEL_ASSERT(g_task_cb[prio].task.handler != OSEL_NULL);
            osel_post_(epool, prio);
        }

        OSEL_INT_UNLOCK();
    }
    while (i != (osel_uint8_t)0);
}

osel_uint8_t osel_mutex_lock(osel_uint8_t prio_ceiling)
{
    return prio_ceiling;
}

void osel_mutex_unlock(osel_uint8_t org_prio)
{
}

void osel_schedule(void)
{
    osel_uint8_t x=0,y=0;
    osel_uint8_t prio =0;
    event_pool_t *epool = OSEL_NULL;
    osel_int8_t pin = osel_curr_prio;

    while ((osel_rdy_grp > 0)
           && (y = osel_unmap_tbl[osel_rdy_grp]
				, x = osel_unmap_tbl[osel_rdy_tbl[y]]
				, (prio = (y << 3) + x) > pin))
    {
        task_cb *tcb = &g_task_cb[prio];

        osel_curr_prio = prio;

        while (list_empty(&(tcb->queue)) != OSEL_TRUE)
        {
            epool = list_entry(tcb->queue.next, event_pool_t, list);

            OSEL_INT_UNLOCK();
            (*(tcb->task.handler))(epool->eblock);
            OSEL_INT_LOCK();

            list_del(&epool->list);

            if (--(epool->eblock->cnt) == 0)
            {
                osel_eblock_free(&(epool->eblock) __EBLOCK_LINE2);
            }

            osel_epool_free(&epool __EPOOL_LINE2);
        }
        if ((osel_rdy_tbl[prio >> 3] &= ~osel_map_tbl[prio & 0x07]) == 0)
        {
            osel_rdy_grp &= ~osel_map_tbl[prio >> 3];
        }
    }

    osel_curr_prio = pin;
}

/**@}**/

